package net.cyue.web.easyquery.core.config;

import net.cyue.util.ReflectUtil;
import net.cyue.util.StringUtil;
import net.cyue.web.easyquery.core.http.handler.api.IWebExceptionHandler;
import net.cyue.web.easyquery.core.http.handler.api.IWebRequestPreHandler;
import net.cyue.web.easyquery.core.http.handler.api.IWebResponseHandler;
import net.cyue.web.easyquery.core.http.handler.api.IWebResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class EasyQueryConfiguration {

    /// 处理器配置组
    protected static final AdditionalConfigGroup CONFIG_GROUP_HANDLER = AdditionalConfigGroup.create(AdditionalConfigGroup.APPLICATION_CONTEXT, "handler");
    /// 日志设置配置组
    protected static final AdditionalConfigGroup CONFIG_GROUP_LOG = AdditionalConfigGroup.create(AdditionalConfigGroup.APPLICATION, "log");

    private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    protected final Logger logger = LoggerFactory.getLogger(this.toString());
    protected final Map<AdditionalConfigItem, IAdditionalConfigItemHandler> additionalConfigItemHandlerMap = new HashMap<>();
    protected Map<String, ConfigItemValue> configItemValueMap = new HashMap<>();
    protected boolean handlerInitialized = false;


    public EasyQueryConfiguration() {
        this.registerDefaultConfigItemHandlers();
    }


    public AdditionalConfigItem[] getAdditionalConfigItems() {
        return this.additionalConfigItemHandlerMap.keySet().toArray(new AdditionalConfigItem[0]);
    }
    public Set<String> getAdditionalConfigItemNameSet() {
        return this.additionalConfigItemHandlerMap.keySet()
            .stream()
            .map(AdditionalConfigItem::getFullName)
            .collect(Collectors.toSet());
    }
    public Map<AdditionalConfigItem, IAdditionalConfigItemHandler> getAdditionalConfigurationHandlerMap() {
        return this.additionalConfigItemHandlerMap;
    }
    public ConfigItemValue[] getConfigItemValues() {
        return this.configItemValueMap
            .values()
            .stream()
            .sorted((o1, o2) -> {
                // 将 附加配置项 排到前面
                if (o1.getType() == o2.getType()) {
                    return 0;
                } else if (o1.getType() == ConfigItemValue.Type.API) {
                    return 1;
                } else {
                    return -1;
                }
            })
            .toArray(ConfigItemValue[]::new);
    }

    /**
     * 合并配置项
     * @param configuration 配置
     */
    public void merge(EasyQueryConfiguration configuration) {
        if (configuration == null) {
            this.logger.warn("EasyQueryConfiguration is null");
            return;
        }
        this.additionalConfigItemHandlerMap.putAll(configuration.additionalConfigItemHandlerMap);
        this.configItemValueMap.putAll(configuration.configItemValueMap);
    }

    private void registerDefaultConfigItemHandlers() {
        if (handlerInitialized) {
            return;
        }
        handlerInitialized = true;
        this.logger.info("Registering default config item handlers...");

        // 上下文路径 配置
        this.registerConfigItem(
            AdditionalConfigItem.create(
                AdditionalConfigGroup.APPLICATION_CONTEXT,
                "path",
                "context path"
            ),
            (ctx, _configItem, contextPathArgs) -> {
                String contextPath = contextPathArgs.length > 0 ? contextPathArgs[0].toString() : "/";
                ctx.setContextPath(contextPath);
            }
        );

        // 全局预处理器
        this.registerConfigItem(
            AdditionalConfigItem.create(
                CONFIG_GROUP_HANDLER,
                "prehandler",
                "全局预处理器"
            ),
            (ctx, _configItem, classNameArgs) -> {
                for (Object className : classNameArgs) {
                    try {
                        Class<?> clz = this.classLoader.loadClass(className.toString());
                        if (!IWebRequestPreHandler.class.isAssignableFrom(clz)) {
                            this.logger.warn("Invalid PreHandler class: {}", className);
                            continue;
                        }
                        IWebRequestPreHandler handler = (IWebRequestPreHandler) ReflectUtil.createInstance(clz);
                        ctx.addRequestPreHandler(handler);
                    } catch (ClassNotFoundException | NoSuchMethodException e) {
                        this.logger.warn(e.getMessage(), e);
                    }
                }
            }
        );

        // 自定义 WebResult 处理器
        this.registerConfigItem(
            AdditionalConfigItem.create(
                CONFIG_GROUP_HANDLER,
                "result",
                "WebResult 处理器"
            ),
            (ctx, _configItem, classNameArgs) -> {
                String className = classNameArgs.length > 0 ? classNameArgs[0].toString() : null;
                ConfigException configException = new ConfigException("Invalid result handler class: " + className);
                if (StringUtil.isBlank(className) || !className.contains(".")) {
                    this.logger.warn("Invalid result handler class: " + className);
                    // className = DefaultWebResultHandler.class.getName();
                    return;
                }
                try {
                    Class<?> clz = this.classLoader.loadClass(className);
                    if (!IWebResultHandler.class.isAssignableFrom(clz)) {
                        throw configException;
                    }
                    IWebResultHandler handler = ReflectUtil.createInstance((Class<IWebResultHandler>) clz);
                    ctx.setResultHandler(handler);
                } catch (ClassNotFoundException | NoSuchMethodException e) {
                    throw configException;
                }
            }
        );

        // 自定义 Response 处理器
        this.registerConfigItem(
            AdditionalConfigItem.create(
                CONFIG_GROUP_HANDLER,
                "response",
                "WebResponse 处理器"
            ),
            (ctx, _configItem, classNameArgs) -> {
                String className = classNameArgs.length > 0 ? classNameArgs[0].toString() : null;
                ConfigException configException = new ConfigException("Invalid response handler class: " + className);
                if (StringUtil.isBlank(className) || !className.contains(".")) {
                    this.logger.warn("Invalid response handler class: " + className);
                    // className = DefaultWebResponseHandler.class.getName();
                    return;
                }
                try {
                    Class<?> clz = this.classLoader.loadClass(className);;
                    if (!IWebResponseHandler.class.isAssignableFrom(clz)) {
                        throw configException;
                    }
                    IWebResponseHandler handler = ReflectUtil.createInstance((Class<IWebResponseHandler>) clz);
                    ctx.setResponseHandler(handler);
                } catch (ClassNotFoundException | NoSuchMethodException e) {
                    throw configException;
                }
            }
        );

        // 自定义 WebException 处理器
        this.registerConfigItem(
            AdditionalConfigItem.create(
                CONFIG_GROUP_HANDLER,
                "exception",
                "WebException 处理器"
            ),
            (ctx, _configItem, classNameArgs) -> {
                String className = classNameArgs.length > 0 ? classNameArgs[0].toString() : null;
                if (StringUtil.isBlank(className) || !className.contains(".")) {
                    this.logger.warn("Invalid exception handler class: " + className);
                    // className = DefaultWebExceptionHandler.class.getName();
                    return;
                }
                ConfigException configException = new ConfigException("Invalid exception handler class: " + className);
                try {
                    Class<?> clz = this.classLoader.loadClass(className);;
                    if (!IWebExceptionHandler.class.isAssignableFrom(clz)) {
                        throw configException;
                    }
                    IWebExceptionHandler handler = ReflectUtil.createInstance((Class<IWebExceptionHandler>) clz);
                    ctx.setExceptionHandler(handler);
                } catch (ClassNotFoundException | NoSuchMethodException e) {
                    throw configException;
                }
            }
        );
    }

    /**
     * 注册自定义配置项
     * @param additionalConfigItem 配置项
     * @param handler 配置项处理器
     */
    public void registerConfigItem(AdditionalConfigItem additionalConfigItem, IAdditionalConfigItemHandler handler) {
        this.additionalConfigItemHandlerMap.put(additionalConfigItem, handler);
    }


}
